/**
 * This file is part of the DbUnit module for NetBeans IDE
 * Copyright (C) 2009 Pavol Pitoňák
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 */

package cz.muni.fi.dbunit;

import java.awt.Dialog;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
import javax.swing.JPanel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.netbeans.api.db.explorer.ConnectionManager;
import org.netbeans.api.db.explorer.DatabaseConnection;
import org.netbeans.api.db.explorer.support.DatabaseExplorerUIs;
import org.netbeans.api.project.Project;
import org.netbeans.spi.project.ui.LogicalViewProvider;
import org.openide.DialogDescriptor;
import org.openide.DialogDisplayer;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.nodes.Index.ArrayChildren;
import org.openide.nodes.Node;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;

/**
 *
 * @author Pavol Pitoňák <pavol@pitonak.com>
 */
public final class DbUnitVisualPanel extends JPanel {

    public static final String DATABASE_URL = "database_url";
    public static final String DATABASE_USERNAME = "database_username";
    public static final String DATABASE_PASSWD = "database_passwd";
    public static final String DATABASE_SCHEMA = "database_schema";
    public static final String DATASET_PATH = "dataset_path";
    public static final String SET_UP_OPERATION = "set_up_operation_method";
    public static final String TEAR_DOWN_OPERATION = "tear_down_operation_method";
    public static final String NEW_DATABASE_TESTER = "new_database_tester_method";
    public static final String GET_DATABASE_TESTER = "get_database_tester_method";
    public static final String CLOSE_CONNECTION = "close_connection_method";

    public static final String operations[] = new String[] {
            NbBundle.getMessage(DbUnitVisualPanel.class, "DbUnit.operations.NONE"),
            NbBundle.getMessage(DbUnitVisualPanel.class, "DbUnit.operations.CLEAN_INSERT"),
            NbBundle.getMessage(DbUnitVisualPanel.class, "DbUnit.operations.REFRESH"),
            NbBundle.getMessage(DbUnitVisualPanel.class, "DbUnit.operations.TRUNCATE"),
            NbBundle.getMessage(DbUnitVisualPanel.class, "DbUnit.operations.DELETE"),
            NbBundle.getMessage(DbUnitVisualPanel.class, "DbUnit.operations.DELETE_ALL"),
            NbBundle.getMessage(DbUnitVisualPanel.class, "DbUnit.operations.UPDATE"),
            NbBundle.getMessage(DbUnitVisualPanel.class, "DbUnit.operations.INSERT")
        };

    
    private class DatabaseOperationComboBoxModel extends AbstractListModel implements ComboBoxModel{
        // 'none' will be selected
        private Object selectedItem = operations[0];

        public int getSize() {
            return operations.length;
        }

        public Object getElementAt(int index) {
            if (index >= getSize() || index < 0) {
                throw new ArrayIndexOutOfBoundsException("index");
            }
            return operations[index];
        }

        public void setSelectedItem(Object anItem) {
            selectedItem = anItem;
        }

        public Object getSelectedItem() {
            return selectedItem;
        }
    }

    private Node node;
    private final List<ChangeListener> listeners = new ArrayList<ChangeListener>();

    public DbUnitVisualPanel(Project p) {
        initComponents();
        DatabaseExplorerUIs.connect(connectionComboBox, ConnectionManager.getDefault());

        LogicalViewProvider lvp = p.getLookup().lookup(LogicalViewProvider.class);
        List<Node> nodes = new ArrayList<Node>();
        Children tmpChildren = lvp.createLogicalView().getChildren();
        Children children = new ArrayChildren();

        if (tmpChildren.findChild("${src.dir}") != null) {
            nodes.add(tmpChildren.findChild("${src.dir}").cloneNode());
        }
        if (tmpChildren.findChild("${test.src.dir}") != null) {
            nodes.add(tmpChildren.findChild("${test.src.dir}").cloneNode());
        }
        if (tmpChildren.findChild("1SourceRoot") != null) {
            nodes.add(tmpChildren.findChild("1SourceRoot").cloneNode());
        }
        if (tmpChildren.findChild("2TestSourceRoot") != null) {
            nodes.add(tmpChildren.findChild("2TestSourceRoot").cloneNode());
        }
        if (tmpChildren.findChild("OtherRoots") != null) {
            nodes.add(tmpChildren.findChild("OtherRoots").cloneNode());
        }
        
        children.add(nodes.toArray(new Node[nodes.size()]));
        node = new AbstractNode(children);

        HelpCtx.setHelpIDString(setUpOperationComboBox, "cz.muni.fi.dbunit.operations");
        HelpCtx.setHelpIDString(tearDownOperationComboBox, "cz.muni.fi.dbunit.operations");
        HelpCtx.setHelpIDString(setUpOperationCheckBox, "cz.muni.fi.dbunit.operations");
        HelpCtx.setHelpIDString(tearDownOperationCheckBox, "cz.muni.fi.dbunit.operations");
    }

    @Override
    public String getName() {
        return NbBundle.getMessage(DbUnitVisualPanel.class, "DatabaseVisualPanel.name");
    }

    /**
     * 
     * @return chosen connection or null if no connection was chosen
     */
    public String getDatabaseUrl() {
        DatabaseConnection connection = (DatabaseConnection) connectionComboBox.getSelectedItem();
        if (connection == null) {
            return null;
        } else {
            return connection.getDatabaseURL();
        }
    }

    /**
     *
     * @return username associated with chosen connection, null if no connection was chosen
     */
    public String getDatabaseUsername() {
        DatabaseConnection connection = (DatabaseConnection) connectionComboBox.getSelectedItem();
        if (connection == null) {
            return null;
        } else {
            return connection.getUser();
        }
    }

    /**
     *
     * @return password associated with chosen connection, null if no connection was chosen
     */
    public String getDatabasePassword() {
        DatabaseConnection connection = (DatabaseConnection) connectionComboBox.getSelectedItem();
        if (connection == null) {
            return null;
        } else {
            return connection.getPassword();
        }
    }

    /**
     * 
     * @return db schema associated with chosen connection, null if no connection was chosen
     */
    public String getDatabaseSchema() {
        DatabaseConnection connection = (DatabaseConnection) connectionComboBox.getSelectedItem();
        if (connection == null) {
            return null;
        } else {
            return connection.getSchema();
        }
    }

    /**
     *
     * @return DataSet path or null if not set
     */
    public String getDataSetPath() {
        return dataSetTextField.getText();
    }

    /**
     *
     * @return set up operation or null if check box is not selected
     */
    public String getSetUpOperation() {
        if (!setUpOperationCheckBox.isSelected()) {
            return null;
        } else {
            return operations[setUpOperationComboBox.getSelectedIndex()];
        }
    }

    /**
     *
     * @return tear down operation or null if check box is not selected
     */
    public String getTearDownOperation() {
        if (!tearDownOperationCheckBox.isSelected()) {
            return null;
        } else {
            return operations[tearDownOperationComboBox.getSelectedIndex()];
        }
    }

    public boolean isNewDatabaseTester() {
        return newDatabaseTesterCheckBox.isSelected();
    }

    public boolean isGetDatabaseTester() {
        return getDatabaseTesterCheckBox.isSelected();
    }

    public boolean isCloseConnection() {
        return closeConnectionCheckBox.isSelected();
    }

    public void setCloseConnection(boolean arg) {
        closeConnectionCheckBox.setSelected(arg);
    }

    public void setGetDatabaseTester(boolean arg) {
        getDatabaseTesterCheckBox.setSelected(arg);
    }

    public void setNewDatabaseTester(boolean arg) {
        newDatabaseTesterCheckBox.setSelected(arg);
    }

    public void setSetUpOperation(String arg) {
        if (arg == null) {
            setUpOperationCheckBox.setSelected(false);
        } else {
            setUpOperationCheckBox.setSelected(true);
            setUpOperationComboBox.setSelectedItem(arg);
        }
    }

    public void setTearDownOperation(String arg) {
        if (arg == null) {
            tearDownOperationCheckBox.setSelected(false);
        } else {
            tearDownOperationCheckBox.setSelected(true);
            tearDownOperationComboBox.setSelectedItem(arg);
        }
    }

    public int getConnectionIndex() {
        return connectionComboBox.getSelectedIndex();
    }

    public void setConnectionIndex(int arg) {
        connectionComboBox.setSelectedIndex(arg);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        connectionLabel = new javax.swing.JLabel();
        connectionComboBox = new javax.swing.JComboBox();
        dataSetLabel = new javax.swing.JLabel();
        dataSetTextField = new javax.swing.JTextField();
        dataSetButton = new javax.swing.JButton();
        generatedCodePanel = new javax.swing.JPanel();
        setUpOperationComboBox = new javax.swing.JComboBox();
        tearDownOperationComboBox = new javax.swing.JComboBox();
        setUpOperationCheckBox = new javax.swing.JCheckBox();
        tearDownOperationCheckBox = new javax.swing.JCheckBox();
        newDatabaseTesterCheckBox = new javax.swing.JCheckBox();
        getDatabaseTesterCheckBox = new javax.swing.JCheckBox();
        closeConnectionCheckBox = new javax.swing.JCheckBox();

        org.openide.awt.Mnemonics.setLocalizedText(connectionLabel, org.openide.util.NbBundle.getMessage(DbUnitVisualPanel.class, "DbUnitVisualPanel.connectionLabel.text")); // NOI18N

        connectionComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));

        org.openide.awt.Mnemonics.setLocalizedText(dataSetLabel, org.openide.util.NbBundle.getMessage(DbUnitVisualPanel.class, "DbUnitVisualPanel.dataSetLabel.text")); // NOI18N

        dataSetTextField.setEditable(false);
        dataSetTextField.setText(org.openide.util.NbBundle.getMessage(DbUnitVisualPanel.class, "DbUnitVisualPanel.dataSetTextField.text")); // NOI18N

        org.openide.awt.Mnemonics.setLocalizedText(dataSetButton, org.openide.util.NbBundle.getMessage(DbUnitVisualPanel.class, "DbUnitVisualPanel.dataSetButton.text")); // NOI18N
        dataSetButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                dataSetButtonActionPerformed(evt);
            }
        });

        generatedCodePanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(DbUnitVisualPanel.class, "DbUnitVisualPanel.generatedCodePanel.border.title"))); // NOI18N

        setUpOperationComboBox.setModel(new DatabaseOperationComboBoxModel());
        setUpOperationComboBox.setEnabled(false);

        tearDownOperationComboBox.setModel(new DatabaseOperationComboBoxModel());
        tearDownOperationComboBox.setEnabled(false);

        org.openide.awt.Mnemonics.setLocalizedText(setUpOperationCheckBox, org.openide.util.NbBundle.getMessage(DbUnitVisualPanel.class, "DbUnitVisualPanel.setUpOperationCheckBox.text")); // NOI18N
        setUpOperationCheckBox.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                setUpOperationCheckBoxStateChanged(evt);
            }
        });
        setUpOperationCheckBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                setUpOperationCheckBoxActionPerformed(evt);
            }
        });

        org.openide.awt.Mnemonics.setLocalizedText(tearDownOperationCheckBox, org.openide.util.NbBundle.getMessage(DbUnitVisualPanel.class, "DbUnitVisualPanel.tearDownOperationCheckBox.text")); // NOI18N
        tearDownOperationCheckBox.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                tearDownOperationCheckBoxStateChanged(evt);
            }
        });
        tearDownOperationCheckBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                tearDownOperationCheckBoxActionPerformed(evt);
            }
        });

        org.openide.awt.Mnemonics.setLocalizedText(newDatabaseTesterCheckBox, org.openide.util.NbBundle.getMessage(DbUnitVisualPanel.class, "DbUnitVisualPanel.newDatabaseTesterCheckBox.text")); // NOI18N

        org.openide.awt.Mnemonics.setLocalizedText(getDatabaseTesterCheckBox, org.openide.util.NbBundle.getMessage(DbUnitVisualPanel.class, "DbUnitVisualPanel.getDatabaseTesterCheckBox.text")); // NOI18N

        org.openide.awt.Mnemonics.setLocalizedText(closeConnectionCheckBox, org.openide.util.NbBundle.getMessage(DbUnitVisualPanel.class, "DbUnitVisualPanel.closeConnectionCheckBox.text")); // NOI18N

        javax.swing.GroupLayout generatedCodePanelLayout = new javax.swing.GroupLayout(generatedCodePanel);
        generatedCodePanel.setLayout(generatedCodePanelLayout);
        generatedCodePanelLayout.setHorizontalGroup(
            generatedCodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(generatedCodePanelLayout.createSequentialGroup()
                .addGroup(generatedCodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(generatedCodePanelLayout.createSequentialGroup()
                        .addGap(8, 8, 8)
                        .addComponent(newDatabaseTesterCheckBox, javax.swing.GroupLayout.DEFAULT_SIZE, 336, Short.MAX_VALUE)
                        .addGap(142, 142, 142))
                    .addGroup(generatedCodePanelLayout.createSequentialGroup()
                        .addContainerGap()
                        .addGroup(generatedCodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(tearDownOperationCheckBox)
                            .addComponent(setUpOperationCheckBox))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(generatedCodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                            .addComponent(setUpOperationComboBox, 0, 314, Short.MAX_VALUE)
                            .addComponent(tearDownOperationComboBox, 0, 314, Short.MAX_VALUE)))
                    .addGroup(generatedCodePanelLayout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(getDatabaseTesterCheckBox))
                    .addGroup(generatedCodePanelLayout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(closeConnectionCheckBox)))
                .addContainerGap())
        );
        generatedCodePanelLayout.setVerticalGroup(
            generatedCodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(generatedCodePanelLayout.createSequentialGroup()
                .addGap(13, 13, 13)
                .addGroup(generatedCodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(setUpOperationCheckBox)
                    .addComponent(setUpOperationComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(generatedCodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(tearDownOperationCheckBox)
                    .addComponent(tearDownOperationComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(newDatabaseTesterCheckBox)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(getDatabaseTesterCheckBox)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(closeConnectionCheckBox)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(generatedCodePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(connectionLabel)
                    .addComponent(dataSetLabel))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addComponent(dataSetTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 305, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(dataSetButton))
                    .addComponent(connectionComboBox, 0, 400, Short.MAX_VALUE)))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(connectionLabel)
                    .addComponent(connectionComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(dataSetLabel)
                    .addComponent(dataSetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(dataSetButton))
                .addGap(12, 12, 12)
                .addComponent(generatedCodePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
        );
    }// </editor-fold>//GEN-END:initComponents

    private void setUpOperationCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_setUpOperationCheckBoxActionPerformed
        setUpOperationComboBox.setEnabled(setUpOperationCheckBox.isSelected());
    }//GEN-LAST:event_setUpOperationCheckBoxActionPerformed

    private void tearDownOperationCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tearDownOperationCheckBoxActionPerformed
        tearDownOperationComboBox.setEnabled(tearDownOperationCheckBox.isSelected());
    }//GEN-LAST:event_tearDownOperationCheckBoxActionPerformed

    private void dataSetButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dataSetButtonActionPerformed
        DataSetChooser myChooser = new DataSetChooser(node);
        final DialogDescriptor dd = new DialogDescriptor(myChooser,
                NbBundle.getMessage(DbUnitVisualPanel.class, "DbUnitVisualPanel.windowTitle"));

        dd.setValid(false);
        myChooser.addPropertyChangeListener(new PropertyChangeListener() {

            public void propertyChange(PropertyChangeEvent evt) {
                if (evt.getPropertyName().equals(DataSetChooser.IS_VALID)) {
                    Object newvalue = evt.getNewValue();
                    if ((newvalue != null) && (newvalue instanceof Boolean)) {
                        dd.setValid(((Boolean) newvalue).booleanValue());
                    }
                }
            }
        });

        Dialog dlg = DialogDisplayer.getDefault().createDialog(dd);
        dlg.getAccessibleContext().setAccessibleDescription(dlg.getTitle());
        dlg.setVisible(true);

        if (dd.getValue() == DialogDescriptor.OK_OPTION) {
            dataSetTextField.setText(myChooser.getFileName());
            fireChange();
        }
    }//GEN-LAST:event_dataSetButtonActionPerformed

    private void setUpOperationCheckBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_setUpOperationCheckBoxStateChanged
        setUpOperationComboBox.setEnabled(setUpOperationCheckBox.isSelected());
    }//GEN-LAST:event_setUpOperationCheckBoxStateChanged

    private void tearDownOperationCheckBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_tearDownOperationCheckBoxStateChanged
        tearDownOperationComboBox.setEnabled(tearDownOperationCheckBox.isSelected());
    }//GEN-LAST:event_tearDownOperationCheckBoxStateChanged

    private void fireChange() {
        ChangeEvent e = new ChangeEvent(this);
        Iterator<ChangeListener> it = listeners.iterator();
        while (it.hasNext()) {
            it.next().stateChanged(e);
        }
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JCheckBox closeConnectionCheckBox;
    private javax.swing.JComboBox connectionComboBox;
    private javax.swing.JLabel connectionLabel;
    private javax.swing.JButton dataSetButton;
    private javax.swing.JLabel dataSetLabel;
    private javax.swing.JTextField dataSetTextField;
    private javax.swing.JPanel generatedCodePanel;
    private javax.swing.JCheckBox getDatabaseTesterCheckBox;
    private javax.swing.JCheckBox newDatabaseTesterCheckBox;
    private javax.swing.JCheckBox setUpOperationCheckBox;
    private javax.swing.JComboBox setUpOperationComboBox;
    private javax.swing.JCheckBox tearDownOperationCheckBox;
    private javax.swing.JComboBox tearDownOperationComboBox;
    // End of variables declaration//GEN-END:variables
}

